#include "c_precompiled.h"
#include "cl_local.h"

template<> ClientSystem *Ogre::Singleton<ClientSystem>::ms_Singleton=0;
ClientSystem client;//global singleton

ClientSystem::ClientSystem(){
	mRunning=false;
	mGame=0;
}
ClientSystem::~ClientSystem(){
	if(mRunning)
		shutdown();
}
void ClientSystem::init(){
	if(mRunning)return;
	///Initialize Ogre
	initRenderer();
	///Setup paths
	initResources();
	///Setup input system so we can read keys
	initInput();

	Gui::getSingleton().init(mOgreWindow,mOgreScene);

	Ogre::Entity *ent=mOgreScene->createEntity("Head","ogrehead.mesh");
	Ogre::SceneNode *node=mOgreScene->getRootSceneNode()->createChildSceneNode("Head");
	node->attachObject(ent);
	node->setPosition(0,0,0);
	mRunning=true;
}
void ClientSystem::shutdown(){
	if(!mRunning)return;
	Gui::getSingleton().shutdown();
	//shutdown input
	if( mInputSystem ){
		mInputSystem->destroyInputObject( mMouse );
		mInputSystem->destroyInputObject( mKeyboard );

		OIS::InputManager::destroyInputSystem();
		mInputSystem = 0;
	}
	//we need to unload the wast amount of resources ogre is using
	mOgreRoot.reset();

	mRunning=false;
}
bool ClientSystem::isRunning(){
	return mRunning;
}
void ClientSystem::initResources(){
	Ogre::ResourceGroupManager *rm=Ogre::ResourceGroupManager::getSingletonPtr();
	rm->addResourceLocation("..\\base","FileSystem");
	rm->addResourceLocation("..\\base\\gui","FileSystem");
	//rm->addResourceLocation("..\\base\\OgreCore.zip","Zip","Bootstrap");
	rm->addResourceLocation(".\\","FileSystem");
	rm->initialiseAllResourceGroups();
}
void ClientSystem::initRenderer(){
	mOgreRoot=OgreRootPtr(new Ogre::Root("","ogre.cfg","ogre.log"));
	
#if defined(_DEBUG)
	mOgreRoot->loadPlugin("RenderSystem_GL_d");
#elif
	mOgreRoot->loadPlugin("RenderSystem_GL");
#endif
	//find a suitable renderer
	Ogre::RenderSystemList *rl=mOgreRoot->getAvailableRenderers();
	Ogre::RenderSystemList::iterator it=rl->begin();
	Ogre::RenderSystem *rs=0;
	while(it!=rl->end()){
		rs=*(it++);
		if(rs->getName().find("OpenGL")!=-1){
			mOgreRoot->setRenderSystem(rs);
			break;
		}
	}
	if(!mOgreRoot->getRenderSystem())
		throw Ogre::Exception(0,"No renderer present!","Client::initRenderer");

	mOgreRoot->initialise(false);//no window is created

	mOgreWindow=rs->createRenderWindow("Main",800,600,false,0);
	mWindowListener=WindowListenerPtr(new WindowListener());
	Ogre::WindowEventUtilities::addWindowEventListener(mOgreWindow,mWindowListener.get());

	//setup scene manager
	mOgreScene=mOgreRoot->createSceneManager(Ogre::ST_INTERIOR,"SceneManager");
	mOgreScene->setAmbientLight(Ogre::ColourValue(1,1,1));

	//setup viewport
	Ogre::Camera *cam=mOgreScene->createCamera("MainCamera");
	cam->setPosition(0,0,500);
	cam->lookAt(0,0,0);
	Ogre::Viewport *vp=mOgreWindow->addViewport(cam);
	cam->setAspectRatio(Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
}
void ClientSystem::initInput(){
	OIS::ParamList pl;
	size_t hwnd = 0;
	std::ostringstream str;

	mOgreWindow->getCustomAttribute("WINDOW", &hwnd);
	str << hwnd;
	pl.insert(std::make_pair(std::string("WINDOW"), str.str()));

	mInputSystem = OIS::InputManager::createInputSystem( pl );
	mKeyboard = static_cast<OIS::Keyboard*>(mInputSystem->createInputObject( OIS::OISKeyboard, false ));
	mKeyboard->setEventCallback(mWindowListener.get());
	mKeyboard->setBuffered(true);
	mMouse = static_cast<OIS::Mouse*>(mInputSystem->createInputObject( OIS::OISMouse, false ));
	mMouse->setEventCallback(mWindowListener.get());
	mMouse->setBuffered(true);
}
void ClientSystem::render(){
	Ogre::WindowEventUtilities::messagePump();
	if(!mOgreRoot->renderOneFrame())
		throw Ogre::Exception(Ogre::Exception::ERR_INTERNAL_ERROR,"Could not render frame!","Client::Render");
}
void ClientSystem::update(){
	if(!mRunning)return;
	try{
		mMouse->capture();
		mKeyboard->capture();
		Gui::getSingleton().update();
		render();
		//update client game (read server states, send commands, etc...)
		if(mGame){
			mGame->update();
			if(mGame->getState()==CGS_DISCONNECTED)
				disconnect();
		}
	}catch(Ogre::Exception &e){
		//windowlistener throws this when window is closed
		if(e.getNumber()==Ogre::Exception::ERR_NOT_IMPLEMENTED)
			shutdown();
	}
}

void ClientSystem::connect(const char *host){
	disconnect();
	//create a new 'game' and connect it to the server
	mGame=new CGMain(host);
}

void ClientSystem::disconnect(){
	if(mGame)delete mGame;
	mGame=0;
}

void ClientSystem::onMouseMove(int relx, int rely){
	Gui::getSingleton().onMouseMove(relx, rely);
}
void ClientSystem::onMouseDown(int x, int y, int button){
	Gui::getSingleton().onMouseDown(x,y,button);
}
void ClientSystem::onMouseUp(int x, int y, int button){
	Gui::getSingleton().onMouseUp(x,y, button);
}
void ClientSystem::onKeyDown(int keycode, int text){
	Gui::getSingleton().onKeyDown(keycode,text);
}
void ClientSystem::onKeyUp(int keycode, int text){
	Gui::getSingleton().onKeyUp(keycode,text);
}

Client &Client::getSingleton(){
	return ClientSystem::getSingleton();
}
Client *Client::getSingletonPtr(){
	return ClientSystem::getSingletonPtr();
}
